/*
 * @Author: Wangjun
 * @Date: 2023-03-20 18:06:06
 * @LastEditTime: 2023-03-21 21:59:04
 * @LastEditors: Wangjun
 * @Description:
 * @FilePath: \libs\expr\op.go
 * hnxr
 */
package expr

import (
	"errors"
	"go/token"
)

type OPer interface {
	Eval(x, y float64) (float64, error)
	String() string
}

//type FuncOP func(x, y float64) (float64, error)

type add struct {
}

func (m *add) String() string {
	return "+"
}

func (m *add) Eval(x, y float64) (float64, error) {
	return x + y, nil
}

type sub struct {
}

func (m *sub) String() string {
	return "-"
}

func (m *sub) Eval(x, y float64) (float64, error) {
	return x - y, nil
}

type mul struct {
}

func (m *mul) String() string {
	return "*"
}

func (m *mul) Eval(x, y float64) (float64, error) {
	return x * y, nil
}

type quo struct {
}

func (m *quo) String() string {
	return "/"
}

func (m *quo) Eval(x, y float64) (float64, error) {
	if y == 0 {
		return 0, errors.New("division by zero")
	}
	return x / y, nil
}

type rem struct {
}

func (m *rem) String() string {
	return "/"
}

func (m *rem) Eval(x, y float64) (float64, error) {
	if y == 0 {
		return 0, errors.New("division by zero")
	}
	return float64(int64(x) % int64(y)), nil
}

type and struct {
}

func (m *and) String() string {
	return "&"
}

func (m *and) Eval(x, y float64) (float64, error) {
	return float64(int64(x) & int64(y)), nil
}

type or struct {
}

func (m *or) String() string {
	return "|"
}

func (m *or) Eval(x, y float64) (float64, error) {
	return float64(int64(x) | int64(y)), nil
}

type land struct {
}

func (m *land) String() string {
	return "&&"
}

func (m *land) Eval(x, y float64) (float64, error) {
	x1 := int(x) != 0
	y1 := int(y) != 0
	if x1 && y1 {
		return 1, nil
	}
	return 0, nil
}

type lor struct {
}

func (m *lor) String() string {
	return "||"
}

func (m *lor) Eval(x, y float64) (float64, error) {
	x1 := int(x) != 0
	y1 := int(y) != 0
	if x1 || y1 {
		return 1, nil
	}
	return 0, nil
}

type xor struct {
}

func (m *xor) String() string {
	return "^"
}

func (m *xor) Eval(x, y float64) (float64, error) {
	return float64(int64(x) ^ int64(y)), nil
}

type shl struct {
}

func (m *shl) String() string {
	return "<<"
}

func (m *shl) Eval(x, y float64) (float64, error) {
	return float64(int64(x) << int64(y)), nil
}

type shr struct {
}

func (m *shr) String() string {
	return ">>"
}

func (m *shr) Eval(x, y float64) (float64, error) {
	return float64(int64(x) >> int64(y)), nil
}

type eql struct {
}

func (m *eql) String() string {
	return "=="
}

func (m *eql) Eval(x, y float64) (float64, error) {
	if x == y {
		return 1, nil
	}
	return 0, nil
}

type gtr struct {
}

func (m *gtr) String() string {
	return ">"
}

func (m *gtr) Eval(x, y float64) (float64, error) {
	if x > y {
		return 1, nil
	}
	return 0, nil
}

type lss struct {
}

func (m *lss) String() string {
	return "<"
}

func (m *lss) Eval(x, y float64) (float64, error) {
	if x < y {
		return 1, nil
	}
	return 0, nil
}

type neq struct {
}

func (m *neq) String() string {
	return "!="
}

func (m *neq) Eval(x, y float64) (float64, error) {
	if x != y {
		return 1, nil
	}
	return 0, nil
}

type leq struct {
}

func (m *leq) String() string {
	return "<="
}

func (m *leq) Eval(x, y float64) (float64, error) {
	if x <= y {
		return 1, nil
	}
	return 0, nil
}

type geq struct {
}

func (m *geq) String() string {
	return ">="
}

func (m *geq) Eval(x, y float64) (float64, error) {
	if x >= y {
		return 1, nil
	}
	return 0, nil
}

var not = new(unaryNot) //非
var neg = new(unarySub) //负数操作符

var OP = map[token.Token]OPer{
	token.ADD:  new(add),
	token.SUB:  new(sub),
	token.MUL:  new(mul),
	token.QUO:  new(quo),
	token.REM:  new(rem),
	token.AND:  new(and),
	token.OR:   new(or),
	token.XOR:  new(xor),
	token.SHL:  new(shl),
	token.SHR:  new(shr),
	token.LAND: new(land),
	token.LOR:  new(lor),
	token.GTR:  new(gtr),
	token.LSS:  new(lss),
	token.NEQ:  new(neq),
	token.EQL:  new(eql),
	token.GEQ:  new(geq),
	token.LEQ:  new(leq),
}

type Evaler interface {
	Eval() (float64, error)
	String() string
}
